import { Application } from "@/core/application/application"
import type { ApplicationInfo } from "@/core/application/application-info"
import { ApplicationActiveProcessor } from "@/core/application/application-active-processor"
import * as _ from "lodash"
import { computed } from "vue"
import type { Serializable } from "@/stores/plugins/persist"

export class ApplicationContext implements Serializable {
  readonly applications: Map<string, Application>

  readonly activeProcessor: ApplicationActiveProcessor

  constructor() {
    this.applications = new Map<string, Application>()
    this.activeProcessor = new ApplicationActiveProcessor(this)
  }

  allApplications() {
    return this.applications
  }

  getApplication(id: string) {
    return this.applications.get(id)
  }

  getApplications(filter: (application: Application) => boolean) {
    return [...this.applications.values()].filter(filter)
  }

  getApplicationsRef(filter: (application: Application) => boolean) {
    return computed(() => this.getApplications(filter))
  }

  register(info: ApplicationInfo) {
    const application = new Application(info, this)
    this.applications.set(application.id, application)
  }

  fromString(value: string): void {
    const json = JSON.parse(value)
    _.forEach(json.applications, (value: any, key: string) => {
      const application = this.applications.get(key)
      if (application) {
        application.fromState(value)
      }
    })
    this.activeProcessor.fromState(json.activeProcessor)
  }

  toString(): string {
    const obj: any = {}
    obj.applications = this.toState4Applications()
    obj.activeProcessor = this.activeProcessor.toState()
    return JSON.stringify(obj)
  }

  private toState4Applications(): any {
    const obj: any = {}
    for (const [key, value] of this.applications) {
      obj[key] = value.toState()
    }
    return obj
  }

  deserialize(value: string): void {
    this.fromString(value)
  }

  serialize(): string {
    return this.toString()
  }
}
